<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <title>ReactiveMixin web component example</title>
    <link rel="stylesheet" href="demos.css" />
  </head>

  <body>
    <!--
    Note: This demo page puts its template and script in the document body,
    which is somewhat unusual, and only necessary to support showing this demo
    inline in the Elix documentation. In a typical page, the template and script
    would go in the document head.
    -->
    <div class="demo padded">
      <template id="incrementDecrementTemplate">
        <button id="decrement">-</button>
        <span id="value"></span>
        <button id="increment">+</button>
      </template>
      <script type="module">
        import {
          defaultState,
          render,
          setState,
          state,
        } from "../src/base/internal.js";
        import ReactiveMixin from "../src/core/ReactiveMixin.js";

        // Create a native web component with reactive behavior.
        class IncrementDecrement extends ReactiveMixin(HTMLElement) {
          // Allow the value property to be set via an attribute.
          attributeChangedCallback(attributeName, oldValue, newValue) {
            if (attributeName === "value") {
              this.value = parseInt(newValue);
            }
          }

          // This property becomes the value of this[state] at constructor time.
          get [defaultState]() {
            return Object.assign(super[defaultState], {
              value: 0,
            });
          }

          // Expose "value" as an attribute.
          static get observedAttributes() {
            return ["value"];
          }

          // Render the current state to the DOM.
          // ReactiveMixin invokes this method when the state changes.
          [render](changed) {
            if (!this.shadowRoot) {
              // First time we render, create the shadow subtree.
              const root = this.attachShadow({ mode: "open" });
              const clone = document.importNode(
                incrementDecrementTemplate.content,
                true
              );
              root.append(clone);
              // Wire up event handlers.
              // @ts-ignore
              root.querySelector("#decrement").addEventListener("click", () => {
                this.value--;
              });
              // @ts-ignore
              root.querySelector("#increment").addEventListener("click", () => {
                this.value++;
              });
            }
            if (changed.value) {
              // Render the state into the shadow.
              // @ts-ignore
              this.shadowRoot.querySelector("#value").textContent = this[
                state
              ].value;
            }
          }

          // Provide a public property that gets/sets state.
          get value() {
            return this[state].value;
          }
          set value(value) {
            this[setState]({ value });
          }
        }

        customElements.define("increment-decrement", IncrementDecrement);
      </script>

      <increment-decrement></increment-decrement>
    </div>
  </body>
</html>
